#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author       : Abmer
# @Date         : 2019-08-06 10:10:20
# @Link         : https://gitee.com/edrik
# @Modified by  : Amber
# @Modified at  : 2019-08-31 09:59:38
# @Version      : v.0.1

import logging
from . import context as ctx
from .error import *
from .capi.mbapi import api
from .capi.mbtypes import *

log = logging.getLogger(__name__)
UTF8 = 'utf-8'


def bytes2str(b: bytes):
    # return b.decode()
    # return bytes.decode(b)
    return str(b, encoding=UTF8)


def str2bytes(s: str):
    # return str.encode(s)
    return bytes(s, encoding=UTF8)


def jv_to_int(jv):
    _es = ctx.ex_state()
    it = INT()
    it.value = jv
    return api.jsToInt(_es, it)


def jv_to_float(jv):
    _es = ctx.ex_state()
    return api.jsToDouble(_es, jv)


def jv_to_str(jv):
    _es = ctx.ex_state()
    return api.jsToStringW(_es, jv)


def jv_to_temp_str(jv):
    _es = ctx.ex_state()
    return api.jsToTempStringW(_es, jv)


def bind_fn_as_javascript(name: str, fn, param=None, arg_count=1):
    '''wkeJsBindFunction and wkeJsBindFunction must call before webviw init.'''
    log.debug('bind_fn_as_javascript %r %r', name, fn)
    name = str2bytes(name)
    api.wkeJsBindFunction(name, fn, param, arg_count)


def js_set_global(name, fn, param=None, arg_count=1):
    _es = ctx.ex_state()

    @FN(JS_VALUE, JS_EXEC_STATE, JS_VALUE, P_JS_VALUE, INT)
    def js_callAsFunction(es, jsValue, pJsValue, arg_count):
        log.debug(es, jsValue, pJsValue, arg_count)
        fn()
        return api.jsInt(0)

    @FN(VOID, P_JS_DATA)
    def finalize(data):
        del data

    data = JsData()
    data.typeName = b'Function'
    data.callAsFunction = js_callAsFunction
    data.finalize = finalize
    p_data = ctypes.byref(data)
    func = api.jsFunction(_es, p_data)

    prop = PCHAR()
    prop.value = 'call_py'
    api.jsSetGlobal(_es, prop, func)


def call_js(fname, args=None, count=1):
    log.debug('call_js', fname, args)
    _es = ctx.ex_state()
    '''
    p_fname = PCHAR()
    p_fname.value = str2bytes(fname)
    log.debug(p_fname.value)
    func = api.jsGetGlobal(es, p_fname)
    '''

    func = api.jsStringW(_es, fname)
    # param = api.jsToStringW(es, args)
    param = None
    jv = api.jsCallGlobal(_es, func, param, count)
    return api.jsToStringW(_es, jv)


def call_js_fail(fname, args, count=1):
    _es = ctx.ex_state()

    @FN(JS_VALUE, JS_EXEC_STATE, JS_VALUE, P_JS_VALUE, INT)
    def js_callAsFunction(es, jsValue, pJsValue, arg_count):
        log.debug(es, jsValue, pJsValue, arg_count)
        return api.jsInt(0)

    @FN(VOID, P_JS_DATA)
    def finalize(data):
        log.debug(data)
        del data

    # create jsData
    jsData = JsData()
    jsData.typeName = str2bytes('Function')
    jsData.callAsFunction = js_callAsFunction
    # jsData.propertyGet=
    # jsData.propertySet=
    jsData.finalize = finalize
    #
    # fn = api.jsFunction(es, jsData)
    fn = api.jsObject(_es, JsData)
    # args = api.jsObject(es, args)
    args = None

    jv = api.jsCallGlobal(_es, fn, args, arg_count)
    out = jv_to_str(jv)
    return out


def call_js_obj(obj_name, fn_name, args=None, arg_count=0):
    _es = ctx.ex_state()
    jv = api.jsCall(_es, obj_name, fn_name, args, arg_count)
    out = jv_to_str(jv)
    return out


def run_js_by_frame(script: str, frame=None):
    webview, frame = ctx.webview(), ctx.main_frame()
    # isInClosure 表示是否在外层包个function() {}形式的闭包
    script = str2bytes(script)
    jv = api.wkeRunJsByFrame(webview, frame, script, True)  #
    out = jv_to_str(jv)
    log.debug('[Result] wkeRunJsByFrame %r %r', jv, out)
    return out


def run_js(script: str):
    webview = ctx.webview()
    jv = api.wkeRunJSW(webview, script)
    out = jv_to_str(jv)
    log.debug('[Result] wkeRunJSW %r %r', jv, out)
    return out
